package com.xdcplus.web.service.qa.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.poi.excel.style.StyleUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xdcplus.etl.schedule.annotation.Job;
import com.xdcplus.etl.schedule.context.JobHelper;
import com.xdcplus.mom.enums.FileType;
import com.xdcplus.mom.pojo.vo.SysBaseDataVO;
import com.xdcplus.mp.service.impl.BaseServiceImpl;
import com.xdcplus.web.common.pojo.dto.QaMtrlBatchReportDTO;
import com.xdcplus.web.common.pojo.entity.qa.*;
import com.xdcplus.web.common.pojo.vo.qa.*;
import com.xdcplus.web.mapper.qa.QaMtrlBatchReportMapper;
import com.xdcplus.web.service.qa.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 质量结批报告(QaMtrlBatchReport)表服务实现类
 *
 * @author Devin.Sang
 * @since 2024-01-24 11:44:30
 */
@Slf4j
@Service("qaMtrlBatchReportService")
public class QaMtrlBatchReportServiceImpl extends BaseServiceImpl<QaMtrlBatchReportMapper, QaMtrlBatchReport, QaMtrlBatchReport, QaMtrlBatchReportVO> implements QaMtrlBatchReportService {

    @Autowired
    protected QaMtrlBatchReportMapper qaMtrlBatchReportMapper;

    @Autowired
    protected TransactionTemplate transactionTemplate;

    @Autowired
    protected QaMtrlBatchReportCrackService qaMtrlBatchReportCrackService;

    @Autowired
    protected QaMtrlBatchReportOpeTimeService qaMtrlBatchReportOpeTimeService;

    @Autowired
    private QaMtrlBatchReportAdverseService qaMtrlBatchReportAdverseService;

    @Autowired
    private QaMtrlBatchReportScreenService qaMtrlBatchReportScreenService;

    @Autowired
    private QaMtrlBatchReportIvSummaryService qaMtrlBatchReportIvSummaryService;
    @Autowired
    private QaMtrlBatchReportElSummaryService qaMtrlBatchReportElSummaryService;
    @Autowired
    private QaMtrlBatchReportPackInfoService qaMtrlBatchReportPackInfoService;
    @Autowired
    private QaMtrlBatchReportIvCountService qaMtrlBatchReportIvCountService;


    private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,
            4,
            0,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(512),
            new ThreadPoolExecutor.DiscardOldestPolicy());


    @Override
    public Map<String, Object> queryReportDetailByCode(String reportCode) {

        List<QaMtrlBatchReport> qaMtrlBatchReports = baseMapper.queryByCode(reportCode);
        Assert.isTrue(ObjectUtil.isNotEmpty(qaMtrlBatchReports), "结批记录不存在");
        QaMtrlBatchReport qaMtrlBatchReport = qaMtrlBatchReports.get(0);

        List<OpenStartAndEndTimeVO> opeStartAndEndTimes = qaMtrlBatchReportMapper.queryOpeStartAndEndTimeByCode(reportCode);
        List<IvSummaryCountVO> ivSummaryCountVOS = qaMtrlBatchReportMapper.queryIvSummaryCountByCode(reportCode);
        IvSummaryCountVO ivSummaryCount = ObjectUtil.isEmpty(ivSummaryCountVOS) ? new IvSummaryCountVO() : ivSummaryCountVOS.get(0);
        String rEta = ivSummaryCount.getReta();

        Map<String, Object> reportMap = new HashMap<>();
        reportMap.put("unpackPlanCrackSummary", qaMtrlBatchReportMapper.queryCrackSummaryByCode(reportCode));
        reportMap.put("factoryStartAndEndTime", opeStartAndEndTimes);
        reportMap.put("adverse", qaMtrlBatchReportMapper.queryQaMtrlBatchReportAdverseByCode(
                reportCode));
        reportMap.put("screen", qaMtrlBatchReportMapper.queryQaMtrlBatchReportScreenByCode(reportCode));
        reportMap.put("ivEta", qaMtrlBatchReportMapper.queryIvSummaryByCode(reportCode));
        reportMap.put("unPackPlanNum", qaMtrlBatchReportMapper.queryUnPackPlanNum(qaMtrlBatchReport.getUnpackPlanCode()));
        reportMap.put("a-", qaMtrlBatchReportMapper.queryElSummaryByCode(reportCode,"a-"));
        reportMap.put("bz", qaMtrlBatchReportMapper.queryElSummaryByCode(reportCode,"bz"));
        reportMap.put("bb", qaMtrlBatchReportMapper.queryElSummaryByCode(reportCode,"bb"));
        reportMap.put("pack", qaMtrlBatchReportMapper.queryPackInfoByCode(reportCode));
        reportMap.put("rEta", rEta);
        reportMap.put("zmColor", qaMtrlBatchReportMapper.queryElSummaryByCode(reportCode,"zmColor"));
        reportMap.put("cSummary", qaMtrlBatchReportMapper.queryElSummaryByCode(reportCode,"cSummary"));
        reportMap.put("ivSummaryCount", ivSummaryCount);

        return reportMap;

    }


    public Map<String, Object> queryReportDetailByCode_old(String reportCode) {
        List<QaMtrlBatchReport> qaMtrlBatchReports = baseMapper.queryByCode(reportCode);
        Assert.isTrue(ObjectUtil.isNotEmpty(qaMtrlBatchReports), "结批记录不存在");
        QaMtrlBatchReport qaMtrlBatchReport = qaMtrlBatchReports.get(0);
        StopWatch stopWatch = new StopWatch();

        // 获取投料信息
        List<OpenStartAndEndTimeVO> opeStartAndEndTimes = qaMtrlBatchReportMapper.queryOpeStartAndEndTime(
                qaMtrlBatchReport.getStartTime(), qaMtrlBatchReport.getEndTime(), qaMtrlBatchReport.getIpqcCode(), qaMtrlBatchReport.getUnpackPlanCode());
        List<OpenStartAndEndTimeVO> zrOpeStartAndEndTimes = filterByOpeCode(opeStartAndEndTimes, "ZR");
        CompletableFuture<List<CrackSummaryVO>> crackSummaryVOFuture = submitCrackSummaryTask(zrOpeStartAndEndTimes);

        stopWatch.start("getUnPackMtrlNum");
        List<QaMtrlBatchReport> unPackMtrlNum = baseMapper.getUnPackMtrlNum(qaMtrlBatchReport.getStartTime(),
                qaMtrlBatchReport.getEndTime());
        stopWatch.stop();

        long total = unPackMtrlNum.stream().mapToLong(QaMtrlBatchReport::getComingMtrlNum).sum();
        Long comingMtrlNum = findComingMtrlNum(unPackMtrlNum, qaMtrlBatchReport);
        double touliaoPercent = calculateDivValue(comingMtrlNum, total, 8, RoundingMode.FLOOR);

        stopWatch.start("qaMtrlBatchReportAdverseService.queryReportDetail");
        List<QaMtrlBatchReportAdverse> qaMtrlBatchReportAdverses = qaMtrlBatchReportAdverseService.queryReportDetail(
                reportCode, qaMtrlBatchReport.getStartTime(), qaMtrlBatchReport.getEndTime(), qaMtrlBatchReport.getProSpec(), touliaoPercent);
        stopWatch.stop();

        stopWatch.start("qaMtrlBatchReportScreenService.queryReportDetail");
        List<OpenStartAndEndTimeVO> swysStartAndEndTme = filterByOpeCode(opeStartAndEndTimes, "SWYS");
        List<QaMtrlBatchReportScreen> qaMtrlBatchReportScreens = queryReportDetailForScreens(reportCode, swysStartAndEndTme, qaMtrlBatchReport);
        stopWatch.stop();

        CompletableFuture<List<IvSummaryVO>> ivSummaryVOFuture = submitIvSummaryTask(swysStartAndEndTme, qaMtrlBatchReport);

        stopWatch.start("qaMtrlBatchReportMapper.queryUnPackPlanNum");
        Long unPackPlanNum = qaMtrlBatchReportMapper.queryUnPackPlanNum(qaMtrlBatchReport.getUnpackPlanCode());
        stopWatch.stop();


        List<OpenStartAndEndTimeVO> csfxStartAndEndTme = filterByOpeCode(opeStartAndEndTimes, "CSFX");
        CompletableFuture<List<ElSummaryVO>> elSummaryVOFuture = submitElSummaryTask(csfxStartAndEndTme, qaMtrlBatchReport);
        CompletableFuture<List<ElSummaryVO>> zmSummaryVOFuture = submitSeparatorSummaryTask(1, csfxStartAndEndTme, qaMtrlBatchReport);
        CompletableFuture<List<ElSummaryVO>> bmSummaryVOFuture = submitSeparatorSummaryTask(2, csfxStartAndEndTme, qaMtrlBatchReport);
        CompletableFuture<List<ElSummaryVO>> cSummaryVOFuture = submitPackProduceOrderCDetailTask(csfxStartAndEndTme, qaMtrlBatchReport);
        CompletableFuture<Long> ivCountVOFuture = submitIvCountTask(csfxStartAndEndTme, qaMtrlBatchReport);
        CompletableFuture<List<ElSummaryVO>> zmColorVOFuture = submitZmColorSummaryTask(1, csfxStartAndEndTme, qaMtrlBatchReport);

        List<SysBaseDataVO> sysBaseDataVOS = qaMtrlBatchReportMapper.queryBaseConfig("IV_POOR_PERFORMANCE");
        Map<String, String> configMap = extractConfig(sysBaseDataVOS);
        CompletableFuture<List<PackInfoVO>> packInfoVOFuture = submitPackInfoTask(csfxStartAndEndTme, qaMtrlBatchReport, configMap);
        CompletableFuture<Double> rEtaFuture = submitEtaTask(csfxStartAndEndTme, qaMtrlBatchReport, configMap);
        CompletableFuture<IvSummaryCountVO> ivSummaryCountVOFuture = submitEtaCountTask(csfxStartAndEndTme, qaMtrlBatchReport, configMap);

        stopWatch.start("getUnpackPlanInfo");
        List<CrackSummaryVO> crackSummaryVOS = getFutureResult(crackSummaryVOFuture);
        stopWatch.stop();

        stopWatch.start("qaMtrlBatchReportMapper.queryEtaGroupByLineNo");
        List<IvSummaryVO> ivSummaryVOS = getFutureResult(ivSummaryVOFuture);
        stopWatch.stop();

        stopWatch.start("qaMtrlBatchReportMapper.queryElSummary");
        List<ElSummaryVO> elSummaryVOS = getFutureResult(elSummaryVOFuture);
        long elSum = elSummaryVOS.stream().mapToLong(ElSummaryVO::getNum).sum();
        for (ElSummaryVO elSummaryVO : elSummaryVOS) {
            elSummaryVO.setRate(calculateDivValue(elSummaryVO.getNum(), elSum, 4, RoundingMode.DOWN));
        }
        List<ElSummaryVO> zmSummaryVOS = getFutureResult(zmSummaryVOFuture);
        List<ElSummaryVO> bmSummaryVOS = getFutureResult(bmSummaryVOFuture);
        long zmSum = zmSummaryVOS.stream().mapToLong(ElSummaryVO::getNum).sum();
        for (ElSummaryVO elSummaryVO : zmSummaryVOS) {
            elSummaryVO.setRate(calculateDivValue(elSummaryVO.getNum(), zmSum, 4, RoundingMode.DOWN));
        }
        long bmSum = bmSummaryVOS.stream().mapToLong(ElSummaryVO::getNum).sum();
        for (ElSummaryVO elSummaryVO : bmSummaryVOS) {
            elSummaryVO.setRate(calculateDivValue(elSummaryVO.getNum(), bmSum, 4, RoundingMode.DOWN));
        }
        List<ElSummaryVO> zmColorVOS = getFutureResult(zmColorVOFuture);
        List<ElSummaryVO> cSummaryVOS = getFutureResult(cSummaryVOFuture, ivCountVOFuture);
        stopWatch.stop();

        stopWatch.start("qaMtrlBatchReportMapper.queryPackInfo");
        List<PackInfoVO> packInfoVOS = getFutureResult(packInfoVOFuture);
        IvSummaryCountVO ivSummaryCountVO = getFutureResult(ivSummaryCountVOFuture);
        Double rEta = getFutureResult(rEtaFuture);
        stopWatch.stop();

        Map<String, Object> reportMap = new HashMap<>();
        reportMap.put("unpackPlanCrackSummary", crackSummaryVOS);
        reportMap.put("factoryStartAndEndTime", opeStartAndEndTimes);
        reportMap.put("adverse", qaMtrlBatchReportAdverses);
        reportMap.put("screen", qaMtrlBatchReportScreens);
        reportMap.put("ivEta", ivSummaryVOS);
        reportMap.put("unPackPlanNum", unPackPlanNum);
        reportMap.put("a-", elSummaryVOS);
        reportMap.put("bz", zmSummaryVOS);
        reportMap.put("bb", bmSummaryVOS);
        reportMap.put("pack", packInfoVOS);
        reportMap.put("rEta", rEta);
        reportMap.put("zmColor", zmColorVOS);
        reportMap.put("cSummary", cSummaryVOS);
        reportMap.put("ivSummaryCount", ivSummaryCountVO);

        for (StopWatch.TaskInfo taskInfo : stopWatch.getTaskInfo()) {
            log.info("task {}---> 耗时：{}", taskInfo.getTaskName(), taskInfo.getTimeSeconds());
        }

        return reportMap;
    }

    @Job("newQaReportCreateHandle")
    @Override
    public void qaReportCreateHandle(String params) {

        Timestamp nowTime = Timestamp.from(Instant.now());

        String jobParam = JobHelper.getJobParam();
        if (ObjectUtil.isNotEmpty(jobParam)) {
            jobParam = jobParam.replace("[","").replace("]","");
            nowTime = Timestamp.valueOf(LocalDateTime.parse(jobParam,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }

        List<String> notEndReports = qaMtrlBatchReportMapper.queryReportCodesNotEnd(nowTime);

        for (String notEndReport : notEndReports) {
            log.info("结批单号: {}",notEndReport);
            deleteReportDetailByCode(notEndReport);
            saveReportDetailByCode(notEndReport);
        }

    }

    @Override
    public void qaReportUpdateHandle() {
        Timestamp nowTime = Timestamp.from(Instant.now());
        List<String> notEndReports = qaMtrlBatchReportMapper.queryReportCodesNotEnd(nowTime);
        for (String notEndReport : notEndReports) {
            log.info("结批单号: {}",notEndReport);
            updateRetaReportDetailByCode(notEndReport);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteReportDetailByCode(String notEndReport) {
        LambdaQueryWrapper<QaMtrlBatchReportCrackSummary> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(QaMtrlBatchReportCrackSummary::getReportCode,notEndReport);
        qaMtrlBatchReportCrackService.remove(queryWrapper);

        LambdaQueryWrapper<QaMtrlBatchReportOpeTime> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(QaMtrlBatchReportOpeTime::getReportCode,notEndReport);
        qaMtrlBatchReportOpeTimeService.remove(queryWrapper1);


        LambdaQueryWrapper<QaMtrlBatchReportAdverse> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.eq(QaMtrlBatchReportAdverse::getReportCode,notEndReport);
        qaMtrlBatchReportAdverseService.remove(queryWrapper2);


        LambdaQueryWrapper<QaMtrlBatchReportScreen> queryWrapper3 = new LambdaQueryWrapper<>();
        queryWrapper3.eq(QaMtrlBatchReportScreen::getReportCode,notEndReport);
        qaMtrlBatchReportScreenService.remove(queryWrapper3);


        LambdaQueryWrapper<QaMtrlBatchReportIvSummary> queryWrapper4 = new LambdaQueryWrapper<>();
        queryWrapper4.eq(QaMtrlBatchReportIvSummary::getReportCode,notEndReport);
        qaMtrlBatchReportIvSummaryService.remove(queryWrapper4);


        LambdaQueryWrapper<QaMtrlBatchReportElSummary> queryWrapper5 = new LambdaQueryWrapper<>();
        queryWrapper5.eq(QaMtrlBatchReportElSummary::getReportCode,notEndReport);
        qaMtrlBatchReportElSummaryService.remove(queryWrapper5);


        LambdaQueryWrapper<QaMtrlBatchReportPackInfo> queryWrapper6 = new LambdaQueryWrapper<>();
        queryWrapper6.eq(QaMtrlBatchReportPackInfo::getReportCode,notEndReport);
        qaMtrlBatchReportPackInfoService.remove(queryWrapper6);

        LambdaQueryWrapper<QaMtrlBatchReportIvCount> queryWrapper7 = new LambdaQueryWrapper<>();
        queryWrapper7.eq(QaMtrlBatchReportIvCount::getReportCode,notEndReport);
        qaMtrlBatchReportIvCountService.remove(queryWrapper7);

    }


    @Override
    public void saveReportDetailByCode(String reportCode) {

        Map<String,Object> reportDetailMap = queryReportDetailByCode_old(reportCode);
        if (reportDetailMap.get("unpackPlanCrackSummary")!=null) {
            List<CrackSummaryVO> crackSummaryVOS = (List<CrackSummaryVO>) reportDetailMap.get("unpackPlanCrackSummary");
            List<QaMtrlBatchReportCrackSummary> summaryVOS = crackSummaryVOS.stream().map(
                    v -> {
                        QaMtrlBatchReportCrackSummary qaMtrlBatchReportCrackSummary = new QaMtrlBatchReportCrackSummary();
                        BeanUtil.copyProperties(v, qaMtrlBatchReportCrackSummary);
                        qaMtrlBatchReportCrackSummary.setReportCode(reportCode);
                        return qaMtrlBatchReportCrackSummary;
                    }
            ).collect(Collectors.toList());
            qaMtrlBatchReportCrackService.saveBatch(summaryVOS);
        }

        if (reportDetailMap.get("factoryStartAndEndTime")!=null) {
            List<OpenStartAndEndTimeVO> openStartAndEndTimeVOS = (List<OpenStartAndEndTimeVO>) reportDetailMap.get("factoryStartAndEndTime");
            List<QaMtrlBatchReportOpeTime> qaMtrlBatchReportOpeTimes = openStartAndEndTimeVOS.stream().map(
                    v -> {
                        QaMtrlBatchReportOpeTime qaMtrlBatchReportOpeTime = new QaMtrlBatchReportOpeTime();
                        BeanUtil.copyProperties(v, qaMtrlBatchReportOpeTime);
                        qaMtrlBatchReportOpeTime.setReportCode(reportCode);
                        return qaMtrlBatchReportOpeTime;
                    }
            ).collect(Collectors.toList());
            qaMtrlBatchReportOpeTimeService.saveBatch(qaMtrlBatchReportOpeTimes);
        }

        if (reportDetailMap.get("adverse")!=null) {
            List<QaMtrlBatchReportAdverse> adverses = (List<QaMtrlBatchReportAdverse>) reportDetailMap.get("adverse");
            for (QaMtrlBatchReportAdverse advers : adverses) {
                advers.setReportCode(reportCode);
            }
            qaMtrlBatchReportAdverseService.saveBatch(adverses);
        }

        if (reportDetailMap.get("screen")!=null) {
            List<QaMtrlBatchReportScreen> qaMtrlBatchReportScreens = (List<QaMtrlBatchReportScreen>) reportDetailMap.get("screen");
            for (QaMtrlBatchReportScreen screen : qaMtrlBatchReportScreens) {
                screen.setReportCode(reportCode);
            }
            qaMtrlBatchReportScreenService.saveBatch(qaMtrlBatchReportScreens);
        }


        if (reportDetailMap.get("ivEta")!=null) {
            List<IvSummaryVO> ivSummaryVOS = (List<IvSummaryVO>) reportDetailMap.get("ivEta");
            List<QaMtrlBatchReportIvSummary> qaMtrlBatchReportIvSummaries = ivSummaryVOS.stream().map(
                    v -> {
                        QaMtrlBatchReportIvSummary qaMtrlBatchReportIvSummary = new QaMtrlBatchReportIvSummary();
                        BeanUtil.copyProperties(v, qaMtrlBatchReportIvSummary);
                        qaMtrlBatchReportIvSummary.setReportCode(reportCode);
                        return qaMtrlBatchReportIvSummary;
                    }
            ).collect(Collectors.toList());
            qaMtrlBatchReportIvSummaryService.saveBatch(qaMtrlBatchReportIvSummaries);
        }

        if (reportDetailMap.get("cSummary")!=null) {
            List<ElSummaryVO> cSummaryVOS = (List<ElSummaryVO>) reportDetailMap.get("cSummary");
            List<QaMtrlBatchReportElSummary> qaMtrlBatchReportElSummaries = cSummaryVOS.stream().map(
                    v -> {
                        QaMtrlBatchReportElSummary qaMtrlBatchReportElSummary = new QaMtrlBatchReportElSummary();
                        BeanUtil.copyProperties(v, qaMtrlBatchReportElSummary);
                        qaMtrlBatchReportElSummary.setReportCode(reportCode);
                        qaMtrlBatchReportElSummary.setReportType("cSummary");
                        return qaMtrlBatchReportElSummary;
                    }
            ).collect(Collectors.toList());
            qaMtrlBatchReportElSummaryService.saveBatch(qaMtrlBatchReportElSummaries);
        }

        if (reportDetailMap.get("a-")!=null) {
            List<ElSummaryVO> elSummaryVOS = (List<ElSummaryVO>) reportDetailMap.get("a-");
            List<QaMtrlBatchReportElSummary> qaMtrlBatchReportElSummaries = elSummaryVOS.stream().map(
                    v -> {
                        QaMtrlBatchReportElSummary qaMtrlBatchReportElSummary = new QaMtrlBatchReportElSummary();
                        BeanUtil.copyProperties(v, qaMtrlBatchReportElSummary);
                        qaMtrlBatchReportElSummary.setReportCode(reportCode);
                        qaMtrlBatchReportElSummary.setReportType("a-");
                        return qaMtrlBatchReportElSummary;
                    }
            ).collect(Collectors.toList());
            qaMtrlBatchReportElSummaryService.saveBatch(qaMtrlBatchReportElSummaries);
        }

        if (reportDetailMap.get("bz")!=null) {
            List<ElSummaryVO> zmSummaryVOS = (List<ElSummaryVO>) reportDetailMap.get("bz");
            List<QaMtrlBatchReportElSummary> qaMtrlBatchReportElSummaries = zmSummaryVOS.stream().map(
                    v -> {
                        QaMtrlBatchReportElSummary qaMtrlBatchReportElSummary = new QaMtrlBatchReportElSummary();
                        BeanUtil.copyProperties(v, qaMtrlBatchReportElSummary);
                        qaMtrlBatchReportElSummary.setReportCode(reportCode);
                        qaMtrlBatchReportElSummary.setReportType("bz");
                        return qaMtrlBatchReportElSummary;
                    }
            ).collect(Collectors.toList());
            qaMtrlBatchReportElSummaryService.saveBatch(qaMtrlBatchReportElSummaries);
        }

        if (reportDetailMap.get("bb")!=null) {
            List<ElSummaryVO> bmSummaryVOS = (List<ElSummaryVO>) reportDetailMap.get("bb");
            List<QaMtrlBatchReportElSummary> qaMtrlBatchReportElSummaries = bmSummaryVOS.stream().map(
                    v -> {
                        QaMtrlBatchReportElSummary qaMtrlBatchReportElSummary = new QaMtrlBatchReportElSummary();
                        BeanUtil.copyProperties(v, qaMtrlBatchReportElSummary);
                        qaMtrlBatchReportElSummary.setReportCode(reportCode);
                        qaMtrlBatchReportElSummary.setReportType("bb");
                        return qaMtrlBatchReportElSummary;
                    }
            ).collect(Collectors.toList());
            qaMtrlBatchReportElSummaryService.saveBatch(qaMtrlBatchReportElSummaries);
        }

        if (reportDetailMap.get("zmColor")!=null) {
            List<ElSummaryVO> zmColor = (List<ElSummaryVO>) reportDetailMap.get("zmColor");
            List<QaMtrlBatchReportElSummary> qaMtrlBatchReportElSummaries = zmColor.stream().map(
                    v -> {
                        QaMtrlBatchReportElSummary qaMtrlBatchReportElSummary = new QaMtrlBatchReportElSummary();
                        BeanUtil.copyProperties(v, qaMtrlBatchReportElSummary);
                        qaMtrlBatchReportElSummary.setReportCode(reportCode);
                        qaMtrlBatchReportElSummary.setReportType("zmColor");
                        return qaMtrlBatchReportElSummary;
                    }
            ).collect(Collectors.toList());
            qaMtrlBatchReportElSummaryService.saveBatch(qaMtrlBatchReportElSummaries);
        }


        if (reportDetailMap.get("pack")!=null) {
            List<PackInfoVO> packInfoVOS = (List<PackInfoVO>) reportDetailMap.get("pack");
            List<QaMtrlBatchReportPackInfo> qaMtrlBatchReportPackInfos = packInfoVOS.stream().map(
                    v -> {
                        QaMtrlBatchReportPackInfo qaMtrlBatchReportPackInfo = new QaMtrlBatchReportPackInfo();
                        BeanUtil.copyProperties(v, qaMtrlBatchReportPackInfo);
                        qaMtrlBatchReportPackInfo.setReportCode(reportCode);
                        return qaMtrlBatchReportPackInfo;
                    }
            ).collect(Collectors.toList());
            qaMtrlBatchReportPackInfoService.saveBatch(qaMtrlBatchReportPackInfos);
        }

        if (reportDetailMap.get("ivSummaryCount")!=null) {
            IvSummaryCountVO ivSummaryCount = (IvSummaryCountVO) reportDetailMap.get("ivSummaryCount");
            QaMtrlBatchReportIvCount qaMtrlBatchReportIvCount = new QaMtrlBatchReportIvCount();
            BeanUtil.copyProperties(ivSummaryCount, qaMtrlBatchReportIvCount);
            qaMtrlBatchReportIvCount.setReportCode(reportCode);
            if (reportDetailMap.get("rEta")!=null) {
                qaMtrlBatchReportIvCount.setReta(reportDetailMap.get("rEta").toString());
            }
            qaMtrlBatchReportIvCountService.save(qaMtrlBatchReportIvCount);
        }

    }

    @Override
    public void updateRetaReportDetailByCode(String reportCode) {

        List<QaMtrlBatchReport> qaMtrlBatchReports = baseMapper.queryByCode(reportCode);
        Assert.isTrue(ObjectUtil.isNotEmpty(qaMtrlBatchReports), "结批记录不存在");
        QaMtrlBatchReport qaMtrlBatchReport = qaMtrlBatchReports.get(0);
        List<OpenStartAndEndTimeVO> opeStartAndEndTimes = qaMtrlBatchReportMapper.queryOpeStartAndEndTime(
                qaMtrlBatchReport.getStartTime(), qaMtrlBatchReport.getEndTime(), qaMtrlBatchReport.getIpqcCode(), qaMtrlBatchReport.getUnpackPlanCode());
        List<OpenStartAndEndTimeVO> csfxStartAndEndTme = filterByOpeCode(opeStartAndEndTimes, "CSFX");
        List<SysBaseDataVO> sysBaseDataVOS = qaMtrlBatchReportMapper.queryBaseConfig("IV_POOR_PERFORMANCE");
        Map<String, String> configMap = extractConfig(sysBaseDataVOS);
        CompletableFuture<Double> rEtaFuture = submitEtaTask(csfxStartAndEndTme, qaMtrlBatchReport, configMap);
        Double rEta = getFutureResult(rEtaFuture);

        transactionTemplate.executeWithoutResult(
                transactionStatus -> qaMtrlBatchReportMapper.updateIvCount(rEta!=null?String.valueOf(rEta):"",reportCode)
        );

    }

    private static String fontName = "microsoft yahei";


    @Override
    public void exportExcelDetail(QaMtrlBatchReportDTO qaMtrlBatchReportDTO, HttpServletResponse response) throws IOException {
        String reportCode = qaMtrlBatchReportDTO.getReportCode();
        String reportTitle = reportCode + "-结批报告";
        List<QaMtrlBatchReport> qaMtrlBatchReports = qaMtrlBatchReportMapper.queryByCode(reportCode);
        Assert.isTrue(ObjectUtil.isNotEmpty(qaMtrlBatchReports),"结批信息不存在");

        QaMtrlBatchReport qaMtrlBatchReport = qaMtrlBatchReports.get(0);

        response.setContentType(FileType.XLSX.getValue());
        response.setHeader("Content-Disposition", "attachment; filename="+reportTitle+".xls");
        AtomicInteger globalRowActomicInt = new AtomicInteger(-1);
        AtomicInteger globalCellActomicInt = new AtomicInteger(-1);

        ServletOutputStream outputStream = response.getOutputStream();
        Map<String, Object> reportDetailByCode = queryReportDetailByCode(reportCode);

        HSSFWorkbook workbook = HSSFWorkbookFactory.createWorkbook();
        HSSFSheet workbookSheet = workbook.createSheet(reportTitle);

        /// 通用单元格标题样式
        CellStyle cellTitleStyle = StyleUtil.createHeadCellStyle(workbook);
        cellTitleStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        cellTitleStyle.setAlignment(HorizontalAlignment.LEFT);
        cellTitleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellTitleStyle.setTopBorderColor((short) 0);
        cellTitleStyle.setBottomBorderColor((short) 0);
        cellTitleStyle.setLeftBorderColor((short) 0);
        cellTitleStyle.setRightBorderColor((short) 0);

        HSSFRow hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 480);
        HSSFCell hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());

        CellStyle headCellStyle = StyleUtil.createHeadCellStyle(workbook);
        headCellStyle.setAlignment(HorizontalAlignment.LEFT);
        headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        Font headerTopFont = StyleUtil.createFont(workbook, (short) 0, (short) 16, fontName);
        headCellStyle.setFont(headerTopFont);
        headCellStyle.setTopBorderColor((short) 0);
        headCellStyle.setBottomBorderColor((short) 0);
        headCellStyle.setLeftBorderColor((short) 0);
        headCellStyle.setRightBorderColor((short) 0);
        headCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());

        hssfRowCell.setCellValue(reportTitle);
        hssfRowCell.setCellStyle(headCellStyle);

        for (int i = 0; i < 30; i++) {
            workbookSheet.setColumnWidth(i,4550);
        }

        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get(), globalRowActomicInt.get(), 0, 14));

        /// 原料批次信息
        createModuleTitile(workbookSheet,workbook,globalRowActomicInt,"1、原料批次");
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get(), globalRowActomicInt.get(), 0, 7));


        createOneModule(workbookSheet,qaMtrlBatchReport,cellTitleStyle,globalRowActomicInt,globalCellActomicInt);
        Long takenApartCount = qaMtrlBatchReportDTO.getTakenApartCount();
        Object unPackPlanNum = takenApartCount;
        createOneModule2(workbookSheet,qaMtrlBatchReport,cellTitleStyle, unPackPlanNum,globalRowActomicInt,globalCellActomicInt);


        createModuleTitile(workbookSheet,workbook,globalRowActomicInt,"2、投料信息");
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get(), globalRowActomicInt.get(), 0, 12));


        createTwoModule(workbookSheet,qaMtrlBatchReport,cellTitleStyle,4,
                takenApartCount,
                (List<CrackSummaryVO>)reportDetailByCode.get("unpackPlanCrackSummary"),
                globalRowActomicInt,globalCellActomicInt);

        /// 合并单元格
        // 引用形式的描述信息：合并单元格
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1, globalRowActomicInt.get(), 0, 0));
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1, globalRowActomicInt.get(), 1, 1));
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1, globalRowActomicInt.get(), 2, 2));
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1, globalRowActomicInt.get(), 3, 3));

        createModuleTitile(workbookSheet,workbook,globalRowActomicInt,"3、过程信息");
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get(), globalRowActomicInt.get(), 0, 6));


        List<QaMtrlBatchReportAdverse> qaMtrlBatchReportAdverses = new ArrayList<>();
        List<OpenStartAndEndTimeVO> qaMtrlBatchReportOpeTimes = new ArrayList<>();
        Map<String, OpenStartAndEndTimeVO> opeTimeMap = new HashMap<>();
        if (reportDetailByCode.get("adverse")!=null) {
            qaMtrlBatchReportAdverses = (List<QaMtrlBatchReportAdverse>) reportDetailByCode.get("adverse");
        }
        if (reportDetailByCode.get("factoryStartAndEndTime")!=null) {
            qaMtrlBatchReportOpeTimes = (List<OpenStartAndEndTimeVO>) reportDetailByCode.get("factoryStartAndEndTime");
            opeTimeMap = qaMtrlBatchReportOpeTimes.stream().collect(
                    HashMap::new,
                    (map, item) -> map.put(item.getOpeCode(), item),
                    HashMap::putAll
            );
        }

        /// 工序生产信息重组
        List<OpePathVO> opePathVOS = qaMtrlBatchReportMapper.queryOpePath();
        for (OpePathVO opePathVO : opePathVOS) {

            String opeCode = opePathVO.getOpeCode();
            String opeName;
            if ("FPCB".equals(opeCode)) {
                opeName = "硅检";
            } else {
                opeName = opePathVO.getOpeName();
            }

            String factoryOpeName = opeName;
            switch (opeName) {
                case "正膜":
                    factoryOpeName = "正面镀膜";
                    break;
                case "背膜":
                    factoryOpeName = "背面镀膜";
                    break;
                case "丝印":
                    factoryOpeName = "丝网印刷";
                    break;
                case "测试分选":
                    factoryOpeName = "分选测试";
                    break;
            }
            String finalFactoryOpeName = factoryOpeName;
            Optional<QaMtrlBatchReportAdverse> qaMtrlBatchReportAdverseOptional =
                    qaMtrlBatchReportAdverses.stream().filter(v->
                    {
                        if (v.getFactoryName() == null) return false;
                        return v.getFactoryName().contains(finalFactoryOpeName);
                    }).findFirst();
            
            if (qaMtrlBatchReportAdverseOptional.isPresent()) {
                QaMtrlBatchReportAdverse qaMtrlBatchReportAdverse = qaMtrlBatchReportAdverseOptional.get();
                opePathVO.setDebriseNum(qaMtrlBatchReportAdverse.getDebriseNum());
                opePathVO.setDebriseRate(getPercentage(qaMtrlBatchReportAdverse.getDebriseNum(),
                        Long.parseLong(unPackPlanNum.toString())));
                opePathVO.setReworkNum(qaMtrlBatchReportAdverse.getReworkNum());
                opePathVO.setReworkRate(getPercentage(qaMtrlBatchReportAdverse.getReworkNum(),
                        Long.parseLong(unPackPlanNum.toString())));
            }

            OpenStartAndEndTimeVO qaMtrlBatchReportOpeTime = opeTimeMap.get(opeCode);
            if (qaMtrlBatchReportOpeTime != null) {
                opePathVO.setStartTime(qaMtrlBatchReportOpeTime.getStartTime());
                opePathVO.setEndTime(qaMtrlBatchReportOpeTime.getEndTime());
            }

        }
        createThreeModule(workbookSheet, qaMtrlBatchReport,
                cellTitleStyle, 7, opePathVOS, Long.parseLong(unPackPlanNum.toString()),globalRowActomicInt,globalCellActomicInt);


        if (reportDetailByCode.get("screen")!=null) {

            hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
            hssfRow.setHeight((short) 360);

            hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
            hssfRow.setHeight((short) 360);

            hssfRowCell = hssfRow.createCell(0);
            hssfRowCell.setCellValue("丝网印刷、网版浆料、平均湿重");
            workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get(), globalRowActomicInt.get(), 0, 13));

            List<QaMtrlBatchReportScreen> qaMtrlBatchReportScreens = (List<QaMtrlBatchReportScreen>) reportDetailByCode.get("screen");
            List<IvSummaryVO> ivSummaryVOS = (List<IvSummaryVO>) reportDetailByCode.get("ivEta");

            Map<String, String> ivEtaMap = new HashMap<>();
            if (ivSummaryVOS != null) {
                ivEtaMap = ivSummaryVOS.stream().collect(
                        HashMap::new,
                        (map, item) -> map.put(item.getLineNo(), item.getEta()),
                        HashMap::putAll
                );
            }

            List<QaMtrlBatchReportScreen> newMtrlBatchReportScreens = new ArrayList<>();
            Map<Long,Long> exsitIds = new HashMap<>();
            qaMtrlBatchReportScreens.stream().collect(
                    Collectors.groupingBy(
                            v->v.getBayId()
                    )
            ).forEach((bayId,list)->{
                QaMtrlBatchReportScreen screen = BeanUtil.copyProperties(list.get(0), QaMtrlBatchReportScreen.class);
                screen.setId(Long.valueOf(screen.getBayId().split("#")[0]));
                screen.setBayId(screen.getBayId().split("#")[1]);
                screen.setSlurryMtrlName(
                        list.stream().map(QaMtrlBatchReportScreen::getSlurryName).collect(Collectors.joining(","))
                );
                newMtrlBatchReportScreens.add(screen);
            });

            createFourModule(workbookSheet, qaMtrlBatchReport,
                    cellTitleStyle, newMtrlBatchReportScreens,
                    globalRowActomicInt,globalCellActomicInt,ivEtaMap);

        }


        createModuleTitile(workbookSheet,workbook,globalRowActomicInt,"4、成品信息");
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get(), globalRowActomicInt.get(), 0, 14));


        IvSummaryCountVO ivSummaryCountVO = (IvSummaryCountVO) reportDetailByCode.get("ivSummaryCount");
        List<PackInfoVO> packInfoVOS = (List<PackInfoVO>) reportDetailByCode.get("pack");
        packInfoVOS.sort(Comparator.comparing(PackInfoVO::getEff).reversed());
        Object rEta =  reportDetailByCode.get("rEta");
        createFiveModule(
                workbookSheet, qaMtrlBatchReport,
                cellTitleStyle, globalRowActomicInt,globalCellActomicInt,
                ivSummaryCountVO,packInfoVOS,rEta.toString(),Long.parseLong(unPackPlanNum.toString())
        );


        createModuleTitile(workbookSheet,workbook,globalRowActomicInt,"5、成品率信息");
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get(), globalRowActomicInt.get(), 0, 14));

        createSixModule(
                workbookSheet, qaMtrlBatchReport,
                cellTitleStyle,
                globalRowActomicInt,
                globalCellActomicInt,
                (List<ElSummaryVO>)reportDetailByCode.get("a-"),
                (List<ElSummaryVO>)reportDetailByCode.get("bz"),
                (List<ElSummaryVO>)reportDetailByCode.get("bb"),
                (List<ElSummaryVO>)reportDetailByCode.get("cSummary"),
                ivSummaryCountVO,
                Long.parseLong(unPackPlanNum.toString())
        );


        workbook.write(outputStream);
        outputStream.flush();
        outputStream.close();
        workbook.close();


    }

    private void createSixModule(HSSFSheet workbookSheet,
                                 QaMtrlBatchReport qaMtrlBatchReport,
                                 CellStyle cellTitleStyle,
                                 AtomicInteger globalRowActomicInt,
                                 AtomicInteger globalCellActomicInt,
                                 List<ElSummaryVO> elSummaryVOS,
                                 List<ElSummaryVO> bz,
                                 List<ElSummaryVO> bb,
                                 List<ElSummaryVO> cSummary, IvSummaryCountVO ivSummaryCountVO, long totalNum) {

        globalCellActomicInt.set(-1);

        HSSFRow hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);

        HSSFCell hssfRowCell = hssfRow.createCell(0);
        hssfRowCell.setCellValue("成品率");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(1);
        hssfRowCell.setCellValue("A-");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(2);
        hssfRowCell.setCellValue("B品（正面检测）");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(3);
        hssfRowCell.setCellValue("B品（背面检测）");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(4);
        hssfRowCell.setCellValue("C品");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(6);
        hssfRowCell.setCellValue("线痕");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(8);
        hssfRowCell.setCellValue("原材料不良（同心圆）");
        hssfRowCell.setCellStyle(cellTitleStyle);

        workbookSheet.addMergedRegion(new CellRangeAddress(
                globalRowActomicInt.get(), globalRowActomicInt.get(), 4, 5));
        workbookSheet.addMergedRegion(new CellRangeAddress(
                globalRowActomicInt.get(), globalRowActomicInt.get(), 6, 7));
        workbookSheet.addMergedRegion(new CellRangeAddress(
                globalRowActomicInt.get(), globalRowActomicInt.get(), 8, 9));

        hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);

        Long elTotalNum = elSummaryVOS.stream().collect(Collectors.summingLong(ElSummaryVO::getNum));
        Long bzTotalNum = bz.stream().collect(Collectors.summingLong(ElSummaryVO::getNum));
        Long bbTotalNum = bb.stream().collect(Collectors.summingLong(ElSummaryVO::getNum));
        ElSummaryVO summaryVO = cSummary.get(0);


        hssfRowCell = hssfRow.createCell(0);
        Double aRate = getRadioHalfEven(
                elSummaryVOS.stream().filter(v -> !"OK".equals(v.getQuality())).collect(Collectors.summingLong(ElSummaryVO::getNum)), elTotalNum);
        Double bzRate = getRadioHalfEven(
                bz.stream().filter(v -> !"Nothing".equals(v.getQuality())).collect(Collectors.summingLong(ElSummaryVO::getNum)), bzTotalNum);
        Double bbRate = getRadioHalfEven(
                bb.stream().filter(v -> !"Nothing".equals(v.getQuality())).collect(Collectors.summingLong(ElSummaryVO::getNum)), bbTotalNum);
        Long lineNum = bb.stream().filter(v -> v.getQuality() != null && v.getQuality().contains("线痕")).collect(Collectors.summingLong(ElSummaryVO::getNum));
        Double lineRate = getRadioHalfEven(
                lineNum, bbTotalNum);
        Long circleNum = elSummaryVOS.stream().filter(v -> "同心圆".equals(v.getQuality())).collect(Collectors.summingLong(ElSummaryVO::getNum));
        Double circleRate = getRadioHalfEven(circleNum, elTotalNum);

        /// ???
        double cRate = summaryVO.getRate();
        Double irevRate = getRadioHalfEven(ivSummaryCountVO.getIrevCount(), totalNum);
        Double rshRate = getRadioHalfEven(ivSummaryCountVO.getRshCount(), totalNum);

        log.info("成品率计算： 100 - aRate{} - bzRate{} - bbRate{} - cRate{} - irevRate{} - rshRate{} + lineRate{} + circleRate{}",
                aRate,bzRate,bbRate,cRate,irevRate,rshRate,lineRate,circleRate);

        hssfRowCell.setCellValue(
                getPercentage(1 - aRate - bzRate   - bbRate  - cRate  - irevRate  - rshRate  + lineRate  + circleRate)
        );

        hssfRowCell = hssfRow.createCell(1);
        hssfRowCell.setCellValue(getPercentage(aRate));

        hssfRowCell = hssfRow.createCell(2);
        hssfRowCell.setCellValue(getPercentage(bzRate));

        hssfRowCell = hssfRow.createCell(3);
        hssfRowCell.setCellValue(getPercentage(bbRate));

        hssfRowCell = hssfRow.createCell(4);
        hssfRowCell.setCellValue(summaryVO.getNum());

        hssfRowCell = hssfRow.createCell(5);
        hssfRowCell.setCellValue(getPercentage(cRate));

        hssfRowCell = hssfRow.createCell(6);
        hssfRowCell.setCellValue(lineNum);

        hssfRowCell = hssfRow.createCell(7);
        hssfRowCell.setCellValue(getPercentage(lineRate));

        hssfRowCell = hssfRow.createCell(8);
        hssfRowCell.setCellValue(circleNum);

        hssfRowCell = hssfRow.createCell(9);
        hssfRowCell.setCellValue(getPercentage(circleRate));

        globalCellActomicInt.set(-1);

        hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);

        hssfRowCell = hssfRow.createCell(0);
        hssfRowCell.setCellValue("A-不良项");

        List<String> elClassify = Arrays.asList("吸盘印", "划伤", "手指印", "黑点", "暗片", "顶齿划伤", "断栅", "边黑", "石墨舟印", "黑斑", "麻点", "隐裂", "石英舟印", "黑角", "氧化脏污");
        workbookSheet.addMergedRegion(new CellRangeAddress(
                globalRowActomicInt.get(), globalRowActomicInt.get(), 0, elClassify.size()*2-1));


        hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);
        globalCellActomicInt.set(-2);
        for (String classify : elClassify) {
            hssfRowCell = hssfRow.createCell(globalCellActomicInt.addAndGet(2));
            hssfRowCell.setCellValue(classify);
            hssfRowCell.setCellStyle(cellTitleStyle);

            workbookSheet.addMergedRegion(new CellRangeAddress(
                    globalRowActomicInt.get(), globalRowActomicInt.get(), globalCellActomicInt.get(), globalCellActomicInt.get()+1)
            );
        }


        hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);
        globalCellActomicInt.set(-1);
        for (String classify : elClassify) {
            hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
            hssfRowCell.setCellValue("数量");
            hssfRowCell.setCellStyle(cellTitleStyle);

            hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
            hssfRowCell.setCellValue("比例");
            hssfRowCell.setCellStyle(cellTitleStyle);

        }

        Map<String, ElSummaryVO> elClassifyMap = elSummaryVOS.stream().collect(
                HashMap::new,
                (map, item) -> map.put(item.getQuality(), item),
                HashMap::putAll
        );

        hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);
        globalCellActomicInt.set(-1);
        for (String classify : elClassify) {
            ElSummaryVO summaryVO1 = elClassifyMap.getOrDefault(classify,new ElSummaryVO());
            hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
            hssfRowCell.setCellValue(summaryVO1.getNum());
            /// A-内部分类的占比
            hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
            hssfRowCell.setCellValue(getPercentage(summaryVO1.getNum(),elTotalNum));
        }


    }

    private void createFiveModule(HSSFSheet workbookSheet, QaMtrlBatchReport qaMtrlBatchReport,
                                  CellStyle cellTitleStyle, AtomicInteger globalRowActomicInt, AtomicInteger globalCellActomicInt,
                                  IvSummaryCountVO ivSummaryCountVO, List<PackInfoVO> packInfoVOS, String rEta, long totalNum) {
        globalCellActomicInt.set(-1);
        int rownum1 = globalRowActomicInt.incrementAndGet();
        HSSFRow hssfRow1 = workbookSheet.createRow(rownum1);
        hssfRow1.setHeight((short) 360);

        int rownum2 = globalRowActomicInt.incrementAndGet();
        HSSFRow hssfRow2 = workbookSheet.createRow(rownum2);
        hssfRow2.setHeight((short) 360);

        int rownum3 = globalRowActomicInt.incrementAndGet();
        HSSFRow hssfRow3 = workbookSheet.createRow(rownum3);
        hssfRow3.setHeight((short) 360);


        for (PackInfoVO packInfoVO : packInfoVOS) {

            int column = globalCellActomicInt.incrementAndGet();
            HSSFCell hssfRowCell = hssfRow1.createCell(column);
            hssfRowCell.setCellValue(packInfoVO.getEff());
            hssfRowCell.setCellStyle(cellTitleStyle);

            hssfRowCell = hssfRow2.createCell(column);
            hssfRowCell.setCellValue(packInfoVO.getPower());
            hssfRowCell.setCellStyle(cellTitleStyle);

            hssfRowCell = hssfRow3.createCell(column);
            hssfRowCell.setCellValue(getPercentage(packInfoVO.getNum(),totalNum));

        }

        int column = globalCellActomicInt.incrementAndGet();
        HSSFCell hssfRowCell = hssfRow1.createCell(column);
        hssfRowCell.setCellValue("平均效率");
        hssfRowCell.setCellStyle(cellTitleStyle);

        workbookSheet.addMergedRegion(new CellRangeAddress(
                rownum1, rownum2, column, column));


        hssfRowCell = hssfRow3.createCell(column);
        hssfRowCell.setCellValue(rEta);


        column = globalCellActomicInt.incrementAndGet();
        hssfRowCell = hssfRow1.createCell(column);
        hssfRowCell.setCellValue("低效");
        hssfRowCell.setCellStyle(cellTitleStyle);

        workbookSheet.addMergedRegion(new CellRangeAddress(
                rownum1, rownum2, column, column));

        hssfRowCell = hssfRow3.createCell(column);
        hssfRowCell.setCellValue(getPercentage(ivSummaryCountVO.getEtaCount(),totalNum));

        column = globalCellActomicInt.incrementAndGet();
        hssfRowCell = hssfRow1.createCell(column);
        hssfRowCell.setCellValue("并联偏小");
        hssfRowCell.setCellStyle(cellTitleStyle);

        workbookSheet.addMergedRegion(new CellRangeAddress(
                rownum1, rownum2, column, column));

        hssfRowCell = hssfRow3.createCell(column);
        hssfRowCell.setCellValue(getPercentage(ivSummaryCountVO.getRshCount(),totalNum));

        column = globalCellActomicInt.incrementAndGet();
        hssfRowCell = hssfRow1.createCell(column);
        hssfRowCell.setCellValue("漏电偏大");
        hssfRowCell.setCellStyle(cellTitleStyle);

        workbookSheet.addMergedRegion(new CellRangeAddress(
                rownum1, rownum2, column, column));

        hssfRowCell = hssfRow3.createCell(column);
        hssfRowCell.setCellValue(getPercentage(ivSummaryCountVO.getIrevCount(),totalNum));
        globalCellActomicInt.set(-1);


    }

    private void createFourModule(HSSFSheet workbookSheet, QaMtrlBatchReport qaMtrlBatchReport,
                                  CellStyle cellTitleStyle, List<QaMtrlBatchReportScreen> newMtrlBatchReportScreens,
                                  AtomicInteger globalRowActomicInt, AtomicInteger globalCellActomicInt, Map<String, String> ivEtaMap) {

        HSSFRow hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);

        HSSFCell hssfRowCell = hssfRow.createCell(0);
        hssfRowCell.setCellValue("线别");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(1);
        hssfRowCell.setCellValue("一道印刷");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(4);
        hssfRowCell.setCellValue("二道印刷");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(7);
        hssfRowCell.setCellValue("三道印刷");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(10);
        hssfRowCell.setCellValue("四道印刷");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(13);
        hssfRowCell.setCellValue("湿重总计");
        hssfRowCell.setCellStyle(cellTitleStyle);
        hssfRowCell = hssfRow.createCell(14);
        hssfRowCell.setCellValue("平均效率");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);
        List<String> titleColumns = Arrays.asList("线别", "网板", "浆料", "湿重", "网板", "浆料", "湿重", "网板", "浆料", "湿重", "网板", "浆料", "湿重");
        for (int i = 0; i < titleColumns.size(); i++) {
            hssfRowCell = hssfRow.createCell(i);
            hssfRowCell.setCellValue(titleColumns.get(i));
            hssfRowCell.setCellStyle(cellTitleStyle);
        }

        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1,
                globalRowActomicInt.get(), 0, 0));
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1,
                globalRowActomicInt.get()-1, 1, 3));
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1,
                globalRowActomicInt.get()-1, 4, 6));
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1,
                globalRowActomicInt.get()-1, 7, 9));
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1,
                globalRowActomicInt.get()-1, 10, 12));

        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1,
                globalRowActomicInt.get(), 13, 13));
        workbookSheet.addMergedRegion(new CellRangeAddress(globalRowActomicInt.get()-1,
                globalRowActomicInt.get(), 14, 14));

        List<Long> idList = newMtrlBatchReportScreens.stream().map(QaMtrlBatchReportScreen::getId)
                .distinct().sorted().collect(Collectors.toList());
        for (Long id : idList) {

            /// 过滤 - 平均效率为空的记录，不写入excel
            if (ObjectUtil.isEmpty(ivEtaMap.get(id.toString()))) {
                continue;
            }

            hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
            hssfRow.setHeight((short) 360);
            List<QaMtrlBatchReportScreen> qaMtrlBatchReportScreens = newMtrlBatchReportScreens.stream().filter(v -> v.getId() == id)
                    .sorted(Comparator.comparing(QaMtrlBatchReportScreen::getBayId)).collect(Collectors.toList());
            globalCellActomicInt.set(0);
            hssfRowCell = hssfRow.createCell(globalCellActomicInt.get());
            hssfRowCell.setCellValue(String.format("%s#",id));

            for (QaMtrlBatchReportScreen qaMtrlBatchReportScreen : qaMtrlBatchReportScreens) {
                hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
                hssfRowCell.setCellValue(qaMtrlBatchReportScreen.getSlurryName());
                hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
                hssfRowCell.setCellValue(qaMtrlBatchReportScreen.getSlurryMtrlName());
                hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
                hssfRowCell.setCellValue(qaMtrlBatchReportScreen.getNetWight());
            }

            hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
            hssfRowCell.setCellValue(
                qaMtrlBatchReportScreens.stream().filter(v->ObjectUtil.isNotEmpty(v.getNetWight()))
                    .collect(Collectors.summingDouble(
                        v->Double.valueOf(v.getNetWight())
                ))
            );
            hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
            hssfRowCell.setCellValue(ivEtaMap.getOrDefault(id.toString(),""));

        }


    }

    private int createThreeModule(HSSFSheet workbookSheet, QaMtrlBatchReport qaMtrlBatchReport, CellStyle cellTitleStyle,
                                  int startRow, List<OpePathVO> opePathVOS, long totalNum,
                                  AtomicInteger globalRowActomicInt, AtomicInteger globalCellActomicInt) {

        List<String> titleColumns = Arrays.asList("工序", "生产开始时间", "生产结束时间", "碎片数量", "比例", "不良返工数量", "比例");
        HSSFRow hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);

        for (int i = 0; i < titleColumns.size(); i++) {
            HSSFCell hssfCell = hssfRow.createCell(i);
            hssfCell.setCellValue(titleColumns.get(i));
            hssfCell.setCellStyle(cellTitleStyle);
        }

        for (OpePathVO opePathVO : opePathVOS) {
            hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
            hssfRow.setHeight((short) 360);

            createMyCell(hssfRow,0,opePathVO.getOpeName());
            createMyCell(hssfRow,1,opePathVO.getStartTime()==null?"":opePathVO.getStartTime().toLocalDateTime().format(
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            ));
            createMyCell(hssfRow,2,opePathVO.getEndTime()==null?"":opePathVO.getEndTime().toLocalDateTime().format(
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            ));
            createMyCell(hssfRow,3, opePathVO.getDebriseNum()==null?"":String.valueOf(opePathVO.getDebriseNum()));
            createMyCell(hssfRow,4,opePathVO.getDebriseRate());
            createMyCell(hssfRow,5, opePathVO.getReworkNum()==null?"":String.valueOf(opePathVO.getReworkNum()));
            createMyCell(hssfRow,6,opePathVO.getReworkRate());
        }

        HSSFRow titleRowTotal = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        titleRowTotal.setHeight((short) 360);
        createMyCell(titleRowTotal,0,"总计");
        createMyCell(titleRowTotal,1,"");
        createMyCell(titleRowTotal,2,"");
        createMyCell(titleRowTotal,3,
                opePathVOS.stream().filter(v->v.getDebriseNum()!=null).collect(Collectors.summingLong(OpePathVO::getDebriseNum)).toString());
        createMyCell(titleRowTotal,4,
                getPercentage(
                        opePathVOS.stream().filter(v->v.getDebriseNum()!=null).collect(Collectors.summingLong(OpePathVO::getDebriseNum)).longValue(),
                        totalNum
                ));
        createMyCell(titleRowTotal,5,
                opePathVOS.stream().filter(v->v.getReworkNum()!=null).collect(Collectors.summingLong(OpePathVO::getReworkNum)).toString());
        createMyCell(titleRowTotal,6,getPercentage(
                opePathVOS.stream().filter(v->v.getReworkNum()!=null).collect(Collectors.summingLong(OpePathVO::getReworkNum)).longValue(),
                totalNum
        ));

        return globalRowActomicInt.get();

    }

    private void createMyCell(HSSFRow titleRow2, int i, String value) {
        HSSFCell titleRow1Cell = titleRow2.createCell(i);
        titleRow1Cell.setCellValue(value);
    }

    private void createTwoModule(HSSFSheet workbookSheet, QaMtrlBatchReport qaMtrlBatchReport,
                                 CellStyle cellTitleStyle, int startRow, Long takenApartCount,
                                 List<CrackSummaryVO> unpackPlanCrackSummary,
                                 AtomicInteger rowAtomic, AtomicInteger globalCellActomicInt) {
        globalCellActomicInt.set(-1);
        HSSFRow hssfRow = workbookSheet.createRow(rowAtomic.incrementAndGet());
        hssfRow.setHeight((short) 360);
        HSSFCell hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue("投料时间");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue(qaMtrlBatchReport.getCreatedTime()
                .toLocalDateTime().format(
                        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                ));


        hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue("投料数量");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue(takenApartCount);

        HSSFRow titleRow2 = workbookSheet.createRow(rowAtomic.incrementAndGet());
        titleRow2.setHeight((short) 360);

        for (CrackSummaryVO crackSummaryVO : unpackPlanCrackSummary) {
            int i = globalCellActomicInt.incrementAndGet();

            HSSFCell hssfCell = hssfRow.createCell(i);
            hssfCell.setCellValue("不良类型");
            hssfCell.setCellStyle(cellTitleStyle);

            hssfRowCell = titleRow2.createCell(i);
            hssfRowCell.setCellValue(crackSummaryVO.getNgName());


            i = globalCellActomicInt.incrementAndGet();
            hssfRowCell = hssfRow.createCell(i);
            hssfRowCell.setCellValue("数量");
            hssfRowCell.setCellStyle(cellTitleStyle);

            hssfRowCell = titleRow2.createCell(i);
            hssfRowCell.setCellValue(crackSummaryVO.getNgNumber());

            i = globalCellActomicInt.incrementAndGet();
            hssfRowCell = hssfRow.createCell(i);
            hssfRowCell.setCellValue("不良比例");
            hssfRowCell.setCellStyle(cellTitleStyle);

            hssfRowCell = titleRow2.createCell(i);
            hssfRowCell.setCellValue(getPercentage(crackSummaryVO.getNgNumber(),takenApartCount));


        }
        globalCellActomicInt.set(-1);


    }

    /**
     * 四舍五入
     * @param ngNumber
     * @param takenApartCount
     * @return
     */
    private Double getRadioHalfEven(Long ngNumber, Long takenApartCount) {
        return takenApartCount <= 0?0.00d:
                BigDecimal.valueOf(ngNumber)
                        .divide(BigDecimal.valueOf(takenApartCount),6,RoundingMode.HALF_EVEN).doubleValue();
    }

    /**
     * 截取
     * @param ngNumber
     * @param takenApartCount
     * @return
     */
    private String getPercentage(Long ngNumber, Long takenApartCount) {
        return takenApartCount <= 0?"0.00%":String.format("%.2f%%",
                BigDecimal.valueOf(ngNumber*100)
                        .divide(BigDecimal.valueOf(takenApartCount),6,RoundingMode.DOWN).doubleValue());
    }
    /**
     * 截取
     * @param ngNumber
     * @param takenApartCount
     * @return
     */
    private String getPercentage(Double ngNumber, Double takenApartCount) {
        return takenApartCount <= 0?"0.00%":String.format("%.2f%%",
                BigDecimal.valueOf(ngNumber*100d)
                        .divide(BigDecimal.valueOf(takenApartCount),6,RoundingMode.DOWN).doubleValue());
    }

    private String getPercentage(Double value) {
        return String.format("%.2f%%",value*100);
    }

    private void createModuleTitile(HSSFSheet workbookSheet, HSSFWorkbook workbook, AtomicInteger globalRowActomicInt, String title) {
        HSSFRow hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);

        hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);

        HSSFCell hssfRowCell = hssfRow.createCell(0);
        hssfRowCell.setCellValue(title);
        CellStyle cellStyle = StyleUtil.createHeadCellStyle(workbook);
        cellStyle.setAlignment(HorizontalAlignment.LEFT);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        Font font = StyleUtil.createFont(workbook, (short) 0, (short) 12, fontName);
//        font.setBold(true);
        cellStyle.setFont(font);
        cellStyle.setTopBorderColor((short) 0);
        cellStyle.setBottomBorderColor((short) 0);
        cellStyle.setLeftBorderColor((short) 0);
        cellStyle.setRightBorderColor((short) 0);
//        cellStyle.setFillForegroundColor((short) 255);
        hssfRowCell.setCellStyle(cellStyle);
    }

    private void createOneModule2(HSSFSheet workbookSheet, QaMtrlBatchReport qaMtrlBatchReport,
                                  CellStyle cellTitleStyle, Object unPackPlanNum,
                                  AtomicInteger globalRowActomicInt, AtomicInteger globalCellActomicInt) {

        globalCellActomicInt.set(-1);

        HSSFRow hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);

        HSSFCell hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue("来料数量");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue(qaMtrlBatchReport.getComingMtrlNum());

        hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue("领料日期");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue(qaMtrlBatchReport.getComingMtrlTime().toLocalDateTime()
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

        hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue("拆包工单");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue(qaMtrlBatchReport.getUnpackPlanCode());


        hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue("计划数量");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(globalCellActomicInt.incrementAndGet());
        hssfRowCell.setCellValue(unPackPlanNum.toString());

        globalCellActomicInt.set(-1);
    }

    private void createOneModule(HSSFSheet workbookSheet, QaMtrlBatchReport qaMtrlBatchReport,
             CellStyle cellTitleStyle, AtomicInteger globalRowActomicInt, AtomicInteger globalCellActomicInt) {

        HSSFRow hssfRow = workbookSheet.createRow(globalRowActomicInt.incrementAndGet());
        hssfRow.setHeight((short) 360);

        HSSFCell hssfRowCell = hssfRow.createCell(0);
        hssfRowCell.setCellValue("供应商");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(1);
        hssfRowCell.setCellValue(qaMtrlBatchReport.getSupplier());

        hssfRowCell = hssfRow.createCell(2);
        hssfRowCell.setCellValue("材料名称");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(3);
        hssfRowCell.setCellValue(qaMtrlBatchReport.getMtrlName());

        hssfRowCell = hssfRow.createCell(4);
        hssfRowCell.setCellValue("规格型号");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(5);
        hssfRowCell.setCellValue(qaMtrlBatchReport.getProSpec());


        hssfRowCell = hssfRow.createCell(6);
        hssfRowCell.setCellValue("批次信息");
        hssfRowCell.setCellStyle(cellTitleStyle);

        hssfRowCell = hssfRow.createCell(7);
        hssfRowCell.setCellValue(qaMtrlBatchReport.getIpqcCode());

    }

    private void updateEndTime(QaMtrlBatchReport qaMtrlBatchReport) {
        if (qaMtrlBatchReport.getEndTime() == null) {
            qaMtrlBatchReport.setEndTime(Timestamp.from(Instant.now()));
        } else {
            LocalDateTime endTime = qaMtrlBatchReport.getEndTime().toLocalDateTime().plusDays(3);
            qaMtrlBatchReport.setEndTime(Timestamp.valueOf(endTime));
        }
    }

    private List<OpenStartAndEndTimeVO> filterByOpeCode(List<OpenStartAndEndTimeVO> list, String opeCode) {
        return list.stream().filter(v -> opeCode.equals(v.getOpeCode())).collect(Collectors.toList());
    }

    private CompletableFuture<List<CrackSummaryVO>> submitCrackSummaryTask(List<OpenStartAndEndTimeVO> zrOpeStartAndEndTimes) {
        if (!CollectionUtils.isEmpty(zrOpeStartAndEndTimes)) {
            return CompletableFuture.supplyAsync(() -> qaMtrlBatchReportMapper.queryZrCrackSummary(zrOpeStartAndEndTimes.get(0), Arrays.asList("隐裂", "硅脱", "崩边")), threadPoolExecutor);
        }
        return CompletableFuture.completedFuture(new ArrayList<>());
    }

    private Long findComingMtrlNum(List<QaMtrlBatchReport> unPackMtrlNum, QaMtrlBatchReport qaMtrlBatchReport) {
        return unPackMtrlNum.stream()
                .filter(v -> v.getUnpackPlanCode().equals(qaMtrlBatchReport.getUnpackPlanCode()))
                .findFirst()
                .map(QaMtrlBatchReport::getComingMtrlNum)
                .orElse(0L);
    }

    private List<QaMtrlBatchReportScreen> queryReportDetailForScreens(String reportCode, List<OpenStartAndEndTimeVO> swysStartAndEndTme, QaMtrlBatchReport qaMtrlBatchReport) {
        if (!CollectionUtils.isEmpty(swysStartAndEndTme)) {
            return qaMtrlBatchReportScreenService.queryReportDetail(reportCode, swysStartAndEndTme.get(0).getStartTime(),
                    swysStartAndEndTme.get(0).getEndTime(), qaMtrlBatchReport.getProSpec());
        }
        return new ArrayList<>();
    }

    private CompletableFuture<List<IvSummaryVO>> submitIvSummaryTask(List<OpenStartAndEndTimeVO> swysStartAndEndTme, QaMtrlBatchReport qaMtrlBatchReport) {
        if (!CollectionUtils.isEmpty(swysStartAndEndTme)) {
            return CompletableFuture.supplyAsync(() -> qaMtrlBatchReportMapper.queryEtaGroupByLineNo(swysStartAndEndTme.get(0), qaMtrlBatchReport.getIpqcCode(), qaMtrlBatchReport.getUnpackPlanCode()), threadPoolExecutor);
        }
        return CompletableFuture.completedFuture(new ArrayList<>());
    }

    private CompletableFuture<List<ElSummaryVO>> submitElSummaryTask(List<OpenStartAndEndTimeVO> csfxStartAndEndTme, QaMtrlBatchReport qaMtrlBatchReport) {
        if (!CollectionUtils.isEmpty(csfxStartAndEndTme)) {
            return CompletableFuture.supplyAsync(() -> qaMtrlBatchReportMapper.queryElSummary(csfxStartAndEndTme.get(0), qaMtrlBatchReport.getIpqcCode(), qaMtrlBatchReport.getUnpackPlanCode()), threadPoolExecutor);
        }
        return CompletableFuture.completedFuture(new ArrayList<>());
    }

    private CompletableFuture<List<ElSummaryVO>> submitSeparatorSummaryTask(int type, List<OpenStartAndEndTimeVO> csfxStartAndEndTme, QaMtrlBatchReport qaMtrlBatchReport) {
        if (!CollectionUtils.isEmpty(csfxStartAndEndTme)) {
            return CompletableFuture.supplyAsync(() -> qaMtrlBatchReportMapper.querySeparatorSummary(type, csfxStartAndEndTme.get(0), qaMtrlBatchReport.getIpqcCode(), qaMtrlBatchReport.getUnpackPlanCode()), threadPoolExecutor);
        }
        return CompletableFuture.completedFuture(new ArrayList<>());
    }

    private CompletableFuture<List<ElSummaryVO>> submitPackProduceOrderCDetailTask(List<OpenStartAndEndTimeVO> csfxStartAndEndTme, QaMtrlBatchReport qaMtrlBatchReport) {
        if (!CollectionUtils.isEmpty(csfxStartAndEndTme)) {
            return CompletableFuture.supplyAsync(() -> qaMtrlBatchReportMapper.queryPackProduceOrderCDetail(csfxStartAndEndTme.get(0), qaMtrlBatchReport.getIpqcCode(), qaMtrlBatchReport.getUnpackPlanCode()), threadPoolExecutor);
        }
        return CompletableFuture.completedFuture(new ArrayList<>());
    }

    private CompletableFuture<Long> submitIvCountTask(List<OpenStartAndEndTimeVO> csfxStartAndEndTme, QaMtrlBatchReport qaMtrlBatchReport) {
        if (!CollectionUtils.isEmpty(csfxStartAndEndTme)) {
            return CompletableFuture.supplyAsync(() -> qaMtrlBatchReportMapper.queryIvCount(csfxStartAndEndTme.get(0), qaMtrlBatchReport.getIpqcCode() ,qaMtrlBatchReport.getUnpackPlanCode()), threadPoolExecutor);
        }
        return CompletableFuture.completedFuture(0L);
    }

    private CompletableFuture<List<ElSummaryVO>> submitZmColorSummaryTask(int type, List<OpenStartAndEndTimeVO> csfxStartAndEndTme, QaMtrlBatchReport qaMtrlBatchReport) {
        if (!CollectionUtils.isEmpty(csfxStartAndEndTme)) {
            return CompletableFuture.supplyAsync(() -> qaMtrlBatchReportMapper.queryZmColorSummary(type, csfxStartAndEndTme.get(0), qaMtrlBatchReport.getIpqcCode(), qaMtrlBatchReport.getUnpackPlanCode()), threadPoolExecutor);
        }
        return CompletableFuture.completedFuture(new ArrayList<>());
    }

    private Map<String, String> extractConfig(List<SysBaseDataVO> sysBaseDataVOS) {
        Map<String, String> configMap = new HashMap<>();
        for (SysBaseDataVO sysBaseDataVO : sysBaseDataVOS) {
            if ("ETA".equals(sysBaseDataVO.getDataItem())) {
                configMap.put("eta", sysBaseDataVO.getDataId());
            } else if ("I_REV2".equals(sysBaseDataVO.getDataItem())) {
                configMap.put("irev", sysBaseDataVO.getDataDesc());
            } else if ("RSHUNT_DF_DR".equals(sysBaseDataVO.getDataItem())) {
                configMap.put("rsh", sysBaseDataVO.getDataId());
            }
        }
        return configMap;
    }

    private CompletableFuture<List<PackInfoVO>> submitPackInfoTask(List<OpenStartAndEndTimeVO> csfxStartAndEndTme, QaMtrlBatchReport qaMtrlBatchReport, Map<String, String> configMap) {
        if (!CollectionUtils.isEmpty(csfxStartAndEndTme)) {
            return CompletableFuture.supplyAsync(() -> qaMtrlBatchReportMapper.queryPackInfo(csfxStartAndEndTme.get(0), qaMtrlBatchReport.getIpqcCode(), qaMtrlBatchReport.getUnpackPlanCode()), threadPoolExecutor);
        }
        return CompletableFuture.completedFuture(new ArrayList<>());
    }

    private CompletableFuture<Double> submitEtaTask(List<OpenStartAndEndTimeVO> csfxStartAndEndTme, QaMtrlBatchReport qaMtrlBatchReport, Map<String, String> configMap) {
        if (!CollectionUtils.isEmpty(csfxStartAndEndTme)) {
            return CompletableFuture.supplyAsync(() -> qaMtrlBatchReportMapper.queryEta(csfxStartAndEndTme.get(0), qaMtrlBatchReport.getIpqcCode(), configMap.get("eta"), qaMtrlBatchReport.getUnpackPlanCode()), threadPoolExecutor);
        }
        return CompletableFuture.completedFuture(0.0);
    }

    private CompletableFuture<IvSummaryCountVO> submitEtaCountTask(List<OpenStartAndEndTimeVO> csfxStartAndEndTme, QaMtrlBatchReport qaMtrlBatchReport, Map<String, String> configMap) {
        if (!CollectionUtils.isEmpty(csfxStartAndEndTme)) {
            return CompletableFuture.supplyAsync(() -> qaMtrlBatchReportMapper.queryEtaCount(csfxStartAndEndTme.get(0), qaMtrlBatchReport.getIpqcCode(), configMap.get("eta"), configMap.get("irev"), configMap.get("rsh"), qaMtrlBatchReport.getUnpackPlanCode()), threadPoolExecutor);
        }
        return CompletableFuture.completedFuture(new IvSummaryCountVO());
    }

    private <T> T getFutureResult(CompletableFuture<T> future) {
        try {
            return future.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    private List<ElSummaryVO> getFutureResult(CompletableFuture<List<ElSummaryVO>> future, CompletableFuture<Long> ivCountVOFuture) {
        try {
            List<ElSummaryVO> result = future.get();
            long ivCount = ivCountVOFuture.get();
            for (ElSummaryVO elSummaryVO : result) {
                elSummaryVO.setRate(calculateDivValue(elSummaryVO.getNum(), ivCount, 4, RoundingMode.DOWN));
            }
            return result;
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 除法
     *
     * @param numerator
     * @param denominator
     * @return
     */
    private double calculateDivValue(long numerator,
                                     long denominator,
                                     int scale,
                                     RoundingMode roundingMode) {
        return numerator > 0 && denominator > 0 ?
                BigDecimal.valueOf(numerator).divide(
                        BigDecimal.valueOf(denominator), scale, roundingMode
                ).doubleValue()
                : 0d;
    }

}
